package gui;

import model.*;
import org.apache.log4j.Logger;
import util.IntPair;
import gui.watcher.Watcher;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 * User: Ansokol
 * Date: 07.02.12
 * Time: 23:41
 * To change this template use File | Settings | File Templates.
 */
public class GuiClient implements MoveProvider, Watcher {
    private final static Logger log = Logger.getLogger(GuiClient.class);

    private final Object monitor = new Object();

    private Set<Figure> usedFigures;
    private JFrame window = new JFrame("Quatro");
    public final JPanel fieldPanel = new JPanel();
    public final JButton[][] fieldButtons = new JButton[4][4];
    private Map<Figure, ImageIcon> icons;
    private JLabel curFigLabel = new JLabel();
    private JPanel upperPanel;
    private JLabel gameStateLabel;
    private Position currentMove;
    private long lastWatch;
    private static final long DELAY = 1000;
    private GameState gs;
    private JButton[] figures;
    private JPanel toolPanel;
    private HumanPlayerState humanPlayerState;
    private Map<JButton, Figure> buttonFigureMap;
    private Map<Figure, JButton> figureButtonMap;

    private Map<JButton, IntPair> buttonToCoordinates;
    private Field currentField;
    private Figure currentFigure;

    public GuiClient() {
        gs=GameState.FIRST_PLAYER_MOVE;
        usedFigures = new HashSet<>();
        currentField = Field.builder().build();

        buttonToCoordinates = new HashMap<>();
        icons = new HashMap<Figure, ImageIcon>(16);
        buttonFigureMap = new HashMap<>(16);
        figureButtonMap = new HashMap<>(16);
        figures = new JButton[16];
        toolPanel = new JPanel();
        toolPanel.setLayout(new GridLayout(2, 8));
        for (int i = 0; i < 16; i++) {
            Figure f = Figure.byCode(i);
            ImageIcon imageIcon = new ImageIcon("images/p" + f.toBinary() + ".png");
            figures[i] = new JButton();
            figures[i].setMinimumSize(new Dimension(90, 90));
            figures[i].setIcon(imageIcon);
            icons.put(f, imageIcon);

            buttonFigureMap.put(figures[i], f);
            figureButtonMap.put(f, figures[i]);
            toolPanel.add(figures[i]);

        }
        upperPanel = new JPanel();
        upperPanel.setLayout(new GridBagLayout());

        GridBagConstraints gbc = new GridBagConstraints();

        window.setSize(900, 700);
        window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        window.getContentPane().setLayout(new GridLayout(2, 1));

        GridLayout mgr = new GridLayout(4, 4);
        fieldPanel.setLayout(mgr);
        for (int j = 0; j < 4; j++) {
            for (int i = 0; i < 4; i++) {
                fieldButtons[i][j] = new JButton();
                fieldPanel.add(fieldButtons[i][j]);
                buttonToCoordinates.put(fieldButtons[i][j], new IntPair(i, j));
            }
        }
        curFigLabel.setIcon(new ImageIcon("images/empty.png"));
        gameStateLabel = new JLabel();
        gameStateLabel.setOpaque(true);
        gameStateLabel.setText("1");

        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 0;
        gbc.weighty = 0;
        upperPanel.add(gameStateLabel, gbc);
        gbc.gridy = 1;
        upperPanel.add(curFigLabel, gbc);
        gbc.gridx = 2;
        gbc.gridy = 0;
        gbc.weightx = 1.0;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.gridheight = 2;
        upperPanel.add(toolPanel, gbc);

        window.getContentPane().add(upperPanel);
        window.getContentPane().add(fieldPanel);
        window.setVisible(true);
        for (int j = 0; j < 4; j++) {
            for (int i = 0; i < 4; i++) {
                fieldButtons[i][j].addActionListener(new FieldListener());
            }
        }
        for (int i = 0; i < 16; i++) {
            figures[i].addActionListener(new ToolListener());
        }
        humanPlayerState = HumanPlayerState.MOVE;
    }

    @Override
    public Position getMove(Field field, Figure figure) {
        watch(new Position(field,figure), gs);
        log.debug("Start getting move");
        for (Figure f : field.getUsedFigures()) {
            figureButtonMap.get(f).setEnabled(false);
        }
        figureButtonMap.get(figure).setEnabled(false);
        this.currentFigure = figure;
        this.currentField = field;
        while (humanPlayerState != HumanPlayerState.SEND) {
            try {
                synchronized (monitor) {
                   monitor.wait();
                }
            } catch (InterruptedException e) {
                log.debug("waiting for user move was interrupted");
            }
        }
        humanPlayerState = HumanPlayerState.WAIT;
        log.debug("end getting move");
        return new Position(currentField, currentFigure);

        //}
    }

    @Override
    public void watch(Position move, GameState state) {
       
        humanPlayerState = HumanPlayerState.WAIT;
        System.out.print(move.getField());
        log.debug("Watcher start watch: " + move);
        long watchTime = System.currentTimeMillis();
        while(watchTime - lastWatch < DELAY){
            try {
                Thread.sleep(DELAY - (watchTime - lastWatch));
            } catch (InterruptedException e) {            
                log.info(e);
            }
            watchTime = System.currentTimeMillis();
        }
        
        for (Figure f : move.getField().getUsedFigures()) {
            figureButtonMap.get(f).setEnabled(false);
        }
        currentMove = move;
        curFigLabel.setIcon(icons.get(move.getFigure()));
        for (int j = 0; j < 4; j++) {
            for (int i = 0; i < 4; i++) {

                fieldButtons[i][j].setIcon(icons.get(move.getField().get(i, j)));
                gameStateLabel.setText(state.toString());
                //  fieldButtons[i][j].setRolloverIcon(icons.get(move.getField().get(i, j)));
            }
        }


        log.debug("end watch");
        lastWatch = System.currentTimeMillis();
        humanPlayerState = HumanPlayerState.MOVE;
    }

    @Override
    public Position getCurrentMove() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    class FieldListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (humanPlayerState == HumanPlayerState.MOVE) {
                IntPair coordinate = buttonToCoordinates.get(e.getSource());
                currentField = currentMove.getField();
                currentField = currentField.addFigure(coordinate.first, coordinate.second, currentMove.getFigure());
                ((JButton) e.getSource()).setIcon(icons.get(currentMove.getFigure()));
                if (currentField.getUsedFigures().size()!=16) {
                    humanPlayerState = HumanPlayerState.SELECT_FIGURE;
                } else {
                    humanPlayerState = HumanPlayerState.SEND;
                    synchronized (monitor){
                        monitor.notifyAll();
                    }
                }

            }
        }
    }

    class ToolListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (humanPlayerState == HumanPlayerState.SELECT_FIGURE) {
                currentFigure = buttonFigureMap.get(e.getSource());
                curFigLabel.setIcon(((JButton) e.getSource()).getIcon());
                humanPlayerState = HumanPlayerState.SEND;
                synchronized (monitor){
                    monitor.notifyAll();
                }
            }
        }
    }

}
